#include <stdint.h>
#include <stdio.h>
#include "crc.h"
#include <time.h>

static int main_ret = 0;
int test_count = 0;
int test_pass = 0;

#define EXPECT_EQ_BASE(equality, expect, actual, format) \
    do {\
        test_count++;\
        if (equality)\
            test_pass++;\
        else {\
            fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual);\
            main_ret = 1;\
        }\
    } while(0)

#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")
#define EXPECT_EQ_HEX(expect, actual, bits) \
        EXPECT_EQ_BASE(hex_compare(expect, actual, bits), expect, ((1ULL<<(bits))-1)&actual, "%08X")

uint8_t hex_compare(uint32_t data1, uint32_t data2, uint8_t bits)
{
    while (bits--)
    {
        if (data1&(1ULL<<(bits+1)) != data2&(1ULL<<(bits+1)))
        {
            return 0;
        }
    }
    return 1;
}

void test_crc(const uint8_t *pdata, uint32_t len, const uint32_t *crc_expct)
{
    uint32_t crc = 0;
    EXPECT_EQ_HEX(crc_expct[0], CRC_CALC(&CRC_CFG_4_ITU, pdata, len), 4);
    EXPECT_EQ_HEX(crc_expct[1], CRC_CALC(&CRC_CFG_5_EPC, pdata, len), 5);
    EXPECT_EQ_HEX(crc_expct[2], CRC_CALC(&CRC_CFG_5_ITU, pdata, len), 5);
    EXPECT_EQ_HEX(crc_expct[3], CRC_CALC(&CRC_CFG_5_USB, pdata, len), 5);
    EXPECT_EQ_HEX(crc_expct[4], CRC_CALC(&CRC_CFG_6_ITU, pdata, len), 6);
    EXPECT_EQ_HEX(crc_expct[5], CRC_CALC(&CRC_CFG_7_MMC, pdata, len), 7);
    EXPECT_EQ_HEX(crc_expct[6], CRC_CALC(&CRC_CFG_8, pdata, len), 8);
    EXPECT_EQ_HEX(crc_expct[7], CRC_CALC(&CRC_CFG_8_ITU, pdata, len), 8);
    EXPECT_EQ_HEX(crc_expct[8], CRC_CALC(&CRC_CFG_8_ROHC, pdata, len), 8);
    EXPECT_EQ_HEX(crc_expct[9], CRC_CALC(&CRC_CFG_8_MAXIM, pdata, len), 8);
    EXPECT_EQ_HEX(crc_expct[10], CRC_CALC(&CRC_CFG_16_IBM, pdata, len), 16);
    EXPECT_EQ_HEX(crc_expct[11], CRC_CALC(&CRC_CFG_16_MAXIM, pdata, len), 16);
    EXPECT_EQ_HEX(crc_expct[12], CRC_CALC(&CRC_CFG_16_USB, pdata, len), 16);
    EXPECT_EQ_HEX(crc_expct[13], CRC_CALC(&CRC_CFG_16_MODBUS, pdata, len), 16);
    EXPECT_EQ_HEX(crc_expct[14], CRC_CALC(&CRC_CFG_16_CCITT, pdata, len), 16);
    EXPECT_EQ_HEX(crc_expct[15], CRC_CALC(&CRC_CFG_16_CCITT_FALSE, pdata, len), 16);
    EXPECT_EQ_HEX(crc_expct[16], CRC_CALC(&CRC_CFG_16_X25, pdata, len), 16);
    EXPECT_EQ_HEX(crc_expct[17], CRC_CALC(&CRC_CFG_16_XMODEM, pdata, len), 16);
    EXPECT_EQ_HEX(crc_expct[18], CRC_CALC(&CRC_CFG_16_DNP, pdata, len), 16);
    EXPECT_EQ_HEX(crc_expct[19], CRC_CALC(&CRC_CFG_32, pdata, len), 32);
    EXPECT_EQ_HEX(crc_expct[20], CRC_CALC(&CRC_CFG_32_MPEG2, pdata, len), 32);

}

void main(void)
{
    int i = 10000;
    uint8_t test[] = {0,1,2,3,4,5,6,7,8,9,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F};
    uint32_t crc_expect[] = {0x0F, 0x16, 0x0F, 0x1E, 0x30, 0x1A, 0x41, 0x14, 0x5A, 0x3C, 0x170A, 0xE8F5, 0x184B, 0xE7B4, 0xBC40, 0x3B37, 0x13E9, 0x513D, 0x10EC, 0xCECEE288, 0xA97AFF4D};
    clock_t start, end;
    start = clock();
    while(i--)
    {
        test_crc(test, sizeof(test)/sizeof(test[0]), crc_expect);
    }
    end = clock();
    printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count);
    printf("time:%lfms\n\r", (double)(end - start)/CLOCKS_PER_SEC*1000);
    return;
}
